//*****************************************
// World of Warcraft 3D Board Game Project
// Team: Cheng, Logan, Thomas, Tyler
//
// Be sure to add comments on the line where you made the changes.
//
//******************************************


#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9tex.h>
#include <ctime>
#include <cmath>
#include <string>

#define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam))
#define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam))
// change the row/column, height/width of screen
#define ROW 10
#define COL 10
#define HEIGHT 480
#define WIDTH  640

int mouseX;
int mouseY;
int curHordePosX, curHordePosY, curAlliancePosX, curAlliancePosY;
float hordeX, hordeY, allianceX, allianceY;
float distance;
char coordinateX[256] = {'\0'}, coordinateY[20] = {'\0'};
bool mouseClick;
int turn; 
double multiX, multiY, boundryX, boundryY;

HINSTANCE hInst;					// holds the instance for this app
HWND wndHandle;						// global window handle

LPD3DXFONT font1;
LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertices
ID3DXMesh *boxMesh, *sphereMesh;

// coloring material
D3DMATERIAL9            red;
D3DMATERIAL9            black;
D3DMATERIAL9			blue;
D3DMATERIAL9			green;

LPDIRECT3D9             pD3D;		// the direct3D objec
LPDIRECT3DDEVICE9       pd3dDevice;	// the direct3d device

// camera variables
D3DXMATRIX matView;					// the view matrix
D3DXMATRIX matProj;					// the projection matrix
D3DXVECTOR3 cameraPosition;			// the position of the camera
D3DXVECTOR3 cameraLook;				// where the camera is pointing
float cameraX = 0.0;
float cameraY = 15.0;
float cameraZ = -15.0;
//3 moveCamera(D3DXVECTOR3(0.0f, 15.0f, -15.0f));

////////////////////////////////////////////// forward declarations
bool    initWindow(HINSTANCE hInstance);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// direct3D functions
HRESULT SetupVB();
bool initDirect3D(HWND hwnd);
void shutdown(void);
void createLighting(void);
void createCamera(float nearClip, float farClip);
void moveCamera(D3DXVECTOR3 vec);
void pointCamera(D3DXVECTOR3 vec);
void doClick(float, float);
void PrintText(char *text);

// Coloring the board
enum {RED, BLACK};

// Draw Functions
void drawSquare(float &x, float &z);
void drawBoard(int x, int y);
void drawHorde(float x, float y);  //TJD
void drawAlliance(float x, float y); //TJD

/*************************************************************************
* WinMain
* entry point
*************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	hordeX = -3.4;
	hordeY = -2.4;
	allianceX = 3.4;
	allianceY = -2.4;
	curHordePosX = 180;
	curHordePosY = 270;
	curAlliancePosX = 460;
	curAlliancePosY = 270;
	mouseClick = false;
	turn = 1;
	// call our function to init and create our window
	if (!initWindow(hInstance))
	{
		MessageBox(NULL, "Unable to create window", "ERROR", MB_OK);
		return false;
	}

	// init direct3d
	if (!initDirect3D(wndHandle))
	{
		MessageBox(NULL, "Unable to init Direct3D", "ERROR", MB_OK);
		shutdown();
		return false;
	}

	// create the lighting for this scene
	createLighting();

	// Create and add the box
	D3DXCreateBox(pd3dDevice, 1.0f, 1.0f, 1.0f, &boxMesh, NULL);
	D3DXComputeNormals(boxMesh, NULL);

	// create and add the sphere
	D3DXCreateSphere(pd3dDevice, 1, 20, 20, &sphereMesh, NULL);
	D3DXComputeNormals(sphereMesh, NULL);

	// Create a D3DX font object
	D3DXCreateFont( pd3dDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &font1 );

	// Main message loop:
	// Enter the message loop
    MSG msg; 
    ZeroMemory( &msg, sizeof(msg) );
    while( msg.message!=WM_QUIT )
    {
		if (msg.message == WM_MOUSEMOVE) 
			{
					//Take Mouse Data and seperate the Loword and Hiword
					mouseX = LOWORD(msg.lParam);
					mouseY = HIWORD(msg.lParam);
					//Scaling Factor for the X and Y values becuase windows in dumb
					//mouseX = mouseX + (.17 * (mouseX/3));
					//mouseY = mouseY + (.43 * (mouseY/3));
					mouseX = mouseX * 1.014263074;
					mouseY = mouseY * 1.0787;
					sprintf_s(coordinateX, "X= %d, Y= %d, HordeX= %d, HordeY= %d, AllianceX= %d, AllianceY= %d, IboundryX= %4.2f, IboundryY= %4.2f, OboundryX= %4.2f, OboundryY= %4.2f", mouseX, mouseY, curHordePosX, curHordePosY, curAlliancePosX, curAlliancePosY, multiX, multiY, boundryX, boundryY);
			}
		// check for messages
		if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
			TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
		// this is called when no messages are pending
		else
		{
			// call our render function
			pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );

			pd3dDevice->BeginScene();

			// create the camera
			createCamera(1.0f, 750.0f);		// near clip plane, far clip plane
			pointCamera(D3DXVECTOR3(0.0f, 0.0f, 0.0f)); // default (0.0f, 0.0f, 0.0f)
			moveCamera(D3DXVECTOR3(cameraX, cameraY, cameraZ));

			
			//UP=(GetAsyncKeyState(0x26))
			//DOWN=(GetAsyncKeyState(0x28))
			//LEFT=(GetAsyncKeyState(0x25))
			//RIGHT=GetAsyncKeyState(0x27))

			/***************  
				  1
			 ___________
			|			|
			|			|
		4	| A		  H |	2	
			|			|
			|			|
			-------------

				  3
			****************/

			//1 moveCamera(D3DXVECTOR3(0.0f, 15.0f, 15.0f)); 
			//2 moveCamera(D3DXVECTOR3(15.0f, 20.0f, 0.0f));
			//3 moveCamera(D3DXVECTOR3(0.0f, 15.0f, -15.0f));
			//4 moveCamera(D3DXVECTOR3(-15.0f, 20.0f, 0.0f));	

			
			////UP KEY, WILL CHANGE WHEN WE HAVE MODES/TURNS
			////Horde Camera
			//if(GetAsyncKeyState(0x26))
			//{
			//	moveCamera(D3DXVECTOR3(15.0f, 20.0f, 0.0f));
			//}

			////DOWN KEY, WILL CHANGE WHEN WE HAVE MODES/TURNS
			////Alliance Camera
			//if(GetAsyncKeyState(0x28))
			//{
			//	moveCamera(D3DXVECTOR3(-15.0f, 20.0f, 0.0f));
			//}
			//
			////LEFT KEY, 1 spot
			//if(GetAsyncKeyState(0x25))
			//{
			//	moveCamera(D3DXVECTOR3(0.0f, 15.0f, 15.0f)); 
			//}


			// call function to draw the board and pieces
			drawBoard(ROW, COL);
			drawHorde(hordeX, hordeY);
			drawAlliance(allianceX, allianceY);
			PrintText(coordinateX);

			pd3dDevice->EndScene();

			pd3dDevice->Present( NULL, NULL, NULL, NULL );	

		}
	}

	// shutdown the directx manager
	shutdown();

	return (int) msg.wParam;
}

/*************************************************************************
* initDirect3D
* initialize direct3D
*************************************************************************/
bool initDirect3D(HWND hwnd)
{
	HRESULT hr;

	if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
	{
		return false;
	}

	D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount  = 1;
	d3dpp.BackBufferHeight = 480;
	d3dpp.BackBufferWidth  = 640;
	d3dpp.hDeviceWindow    = hwnd;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
                             D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                             &d3dpp, &pd3dDevice );
	if FAILED (hr)
    {
        return false;
    }

	// Set the default render states
	pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
	pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

	return true;
}

/*************************************************************************
* createLighting
* sets the lights for this scene
*************************************************************************/
void createLighting(void)
{
	// set the ambient lighting to red
	pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 0, 0));

	// Create and turn on a directional light
	D3DLIGHT9 light;
    D3DXVECTOR3 vDir( 0.3f, 0.0f, 0.0f );
    light.Type         = D3DLIGHT_DIRECTIONAL;
    light.Diffuse.r    = light.Diffuse.g  = light.Diffuse.b  = 0.5f;
    light.Ambient.r    = light.Ambient.g  = light.Ambient.b  = 0.3f;
    D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vDir );
    light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
    light.Range        = sqrtf(FLT_MAX);
    pd3dDevice->SetLight(0, &light );
    pd3dDevice->LightEnable(0, TRUE );

	// red
	ZeroMemory(&red, sizeof(D3DMATERIAL9));
	red.Diffuse.r = 1.0f;
	red.Ambient.r = 1.0f;
	red.Diffuse.g = 0.0f;
	red.Ambient.g = 0.0f;
	red.Diffuse.b = 0.0f;
	red.Ambient.b = 0.0f;
	red.Power = 8.0f;

	// black
	ZeroMemory(&black, sizeof(D3DMATERIAL9));
	black.Diffuse.r = 0.0f;
	black.Ambient.r = 0.0f;
	black.Diffuse.g = 0.0f;
	black.Ambient.g = 0.0f;
	black.Diffuse.b = 0.0f;
	black.Ambient.b = 0.0f;
	black.Power = 8.0f;	

	// blue
	ZeroMemory(&blue, sizeof(D3DMATERIAL9));
	blue.Diffuse.r = 0.0f;
	blue.Ambient.r = 0.0f;
	blue.Diffuse.g = 0.0f;
	blue.Ambient.g = 0.0f;
	blue.Diffuse.b = 1.0f;
	blue.Ambient.b = 1.0f;
	blue.Power = 8.0f;

	// green
	ZeroMemory(&green, sizeof(D3DMATERIAL9));
	green.Diffuse.r = 0.0f;
	green.Ambient.r = 0.0f;
	green.Diffuse.g = 1.0f;
	green.Ambient.g = 1.0f;
	green.Diffuse.b = 0.0f;
	green.Ambient.b = 0.0f;
	green.Power = 8.0f;
}

/*************************************************************************
* shutdown
* releases the direct3d interfaces
*************************************************************************/
void shutdown(void)
{
    if( pd3dDevice != NULL) 
	{
        pd3dDevice->Release();
		pd3dDevice = NULL;
	}
    if( pD3D != NULL)
	{
        pD3D->Release();
		pD3D = NULL;
	}
}

/*************************************************************************
* initWindow
* creates and shows a 640x480 window
*************************************************************************/
bool initWindow(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= 0;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= "World of Warcraft - Board Game";
	wcex.hIconSm		= 0;
	RegisterClassEx(&wcex);

	wndHandle = CreateWindow("World of Warcraft - Board Game", 
							 "World of Warcraft - Board Game", 
							 WS_OVERLAPPEDWINDOW,
							 CW_USEDEFAULT, 
							 CW_USEDEFAULT, 
							 WIDTH, 
							 HEIGHT, 
							 NULL, 
							 NULL, 
							 hInstance, 
							 NULL);
   if (!wndHandle)
      return false;
   
   ShowWindow(wndHandle, SW_SHOW);
   UpdateWindow(wndHandle);

   return true;
}

/*************************************************************************
* WndProc
* the windows procedure for this application
*************************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		//case VK_UP:
		//	break;
		//case VK_DOWN:
		//	break;
		//case VK_LEFT:
		//	break;
		//case VK_RIGHT:
		//	break;

		case WM_LBUTTONDOWN: 
			//OFF
			//Spit lParam into loword and hiword.
			//int y = lParam >> 16;
			//int x = lParam & 0xFFFF;
			mouseClick = true;
			doClick(mouseX, mouseY);
			break;

		//3 moveCamera(D3DXVECTOR3(0.0f, 15.0f, -15.0f));
		case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_UP:
			cameraY -= 1.5;
			break;
		case VK_DOWN:
			cameraY += 1.5;
			break;

			//NEED TO FIX HOW IT PUSHES AWAY Z WHEN MOVING -TJD
		case VK_LEFT:
			cameraX -= 1.5;
			break;
		case VK_RIGHT:
			cameraX += 1.5;
			break;
		}
	}


	return DefWindowProc(hWnd, message, wParam, lParam);
}

/*************************************************************************
* createCamera
* creates a virtual camera
*************************************************************************/
void createCamera(float nearClip, float farClip)
{
	//Here we specify the field of view, aspect ration and near and far clipping planes.
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 640/480, nearClip, farClip);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

}

/*************************************************************************
* moveCamera
* moves the camera to a position specified by the vector passed as a 
* parameter
*************************************************************************/
void moveCamera(D3DXVECTOR3 vec)
{
	cameraPosition = vec;
}

/*************************************************************************
* pointCamera
* points the camera a location specified by the passed vector
*************************************************************************/
void pointCamera(D3DXVECTOR3 vec)
{
	cameraLook = vec;

	D3DXMatrixLookAtLH(&matView, &cameraPosition,		//Camera Position
                                 &cameraLook,		//Look At Position
                                 &D3DXVECTOR3(0.0f, 1.0f, 0.0f));		//Up Direction

	pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
}

void drawSquare(float &x, float &z)
{

	D3DXMATRIX meshMat, meshScale, meshRotate, meshTranslate;

	D3DXMatrixTranslation(&meshTranslate, x, 0.0, z);

	//D3DXMatrixRotationY(&meshRotate, timeGetTime()/500.0f);

	D3DXMatrixScaling(&meshScale, 1.0f, 1.0f, 1.0f);

	
	D3DXMatrixMultiply(&meshMat, &meshScale, &meshTranslate);
	//D3DXMatrixMultiply(&meshMat, &meshMat, &meshRotate);

	pd3dDevice->SetTransform(D3DTS_WORLD, &meshMat);

	boxMesh->DrawSubset(0);		
}

// In order to draw equal on both side, x and y is divided by 2
void drawBoard(int x, int y)
{
	int colorBox = BLACK;
	for(float r = -4.5; r <= 4.5; r++)
	{
			if(colorBox == BLACK)
			{
				pd3dDevice->SetMaterial(&black);
				colorBox = RED;
			}
			else if(colorBox == RED)
			{
				pd3dDevice->SetMaterial(&red);
				colorBox = BLACK;
			}
		for(float c = -5; c < 5; c++)
		{
			if(colorBox == BLACK)
			{
				pd3dDevice->SetMaterial(&black);
				colorBox = RED;
			}
			else if(colorBox == RED)
			{
				pd3dDevice->SetMaterial(&red);
				colorBox = BLACK;
			}
			drawSquare(r, c);
		}
	}
}
// Draw Horde toons
// Add by Cheng, draw horde as sphere for testing purpose.
void drawHorde(float x, float y)
{
	D3DXMATRIX meshMat, meshScale, meshRotate, meshTranslate;

	D3DXMatrixTranslation(&meshTranslate, x, 1.0f, y);
	//D3DXMatrixRotationY(&meshRotate, timeGetTime()/500.0f);
	D3DXMatrixScaling(&meshScale, 0.4f, 0.4f, 0.4f);

	D3DXMatrixMultiply(&meshMat, &meshScale, &meshTranslate);
	//D3DXMatrixMultiply(&meshMat, &meshMat, &meshRotate);

	pd3dDevice->SetTransform(D3DTS_WORLD, &meshMat);

	pd3dDevice->SetMaterial(&blue);

	sphereMesh->DrawSubset(0);
}


//Draw Alliance toons -- TJD, modify by Cheng
void drawAlliance(float x, float y)
{
	D3DXMATRIX meshMat, meshScale, meshRotate, meshTranslate;

	D3DXMatrixTranslation(&meshTranslate, x, 1.0f, y);
	//D3DXMatrixRotationY(&meshRotate, timeGetTime()/500.0f);
	D3DXMatrixScaling(&meshScale, 0.4f, 0.4f, 0.4f);

	D3DXMatrixMultiply(&meshMat, &meshScale, &meshTranslate);
	//D3DXMatrixMultiply(&meshMat, &meshMat, &meshRotate);

	pd3dDevice->SetTransform(D3DTS_WORLD, &meshMat);

	pd3dDevice->SetMaterial(&green);

	sphereMesh->DrawSubset(0);
}

void doClick(float x, float y)
{
	if(mouseClick)
	{
		boundryX = 32;
		boundryY = 13;
		multiX = 32;
		multiY = 13;
		if (turn == 1)
		{
			for (int p = hordeY; p <= 5; p++)
			{
				multiX = multiX * 1.035;
				multiY = multiY * 1.072;
			}
			multiX = multiX / 2;
			multiY = multiY / 2;
			if (fabs(curHordePosY - y) < multiY)
			{
				if (fabs(curHordePosX - x) > multiX && fabs(curHordePosX - x) < (multiX * 3))
				{
					if (curHordePosX - x > 0)
					{
						hordeX--;
						curHordePosX = curHordePosX - (multiX * 2);
						turn++;
					}
					else if (x - curHordePosX > 0)
					{
						hordeX++;
						curHordePosX = curHordePosX + (multiX * 2);
						turn++;
					}
				}
			}
			else if (fabs(curHordePosY - y) > multiY && fabs(curHordePosX - x) < multiX)
			{
				if (curHordePosY - y > 0)
				{
					for (int p = hordeY + 1; p <= 5; p++)
					{
						boundryX = boundryX * 1.035;
						boundryY = boundryY * 1.072;
					}
					if (fabs(curHordePosY - y) < (boundryY + multiY))
					{
						hordeY++;
						curHordePosY = curHordePosY - (multiY + (boundryY / 2));
						turn++;
					}
				}
				else if (y - curHordePosY > 0)
				{
					for (int p = hordeY - 1; p <= 5; p++)
					{
						boundryX = boundryX * 1.035;
						boundryY = boundryY * 1.072;
					}
					if (fabs(curHordePosY - y) < (boundryY + multiY))
					{
						hordeY--;
						curHordePosY = curHordePosY + (multiY + (boundryY / 2));
						turn++;
					}
				}
			}
		}
		else
		{
			for (int p = allianceY; p <= 5; p++)
			{
				multiX = multiX * 1.035;
				multiY = multiY * 1.072;
			}
			multiX = multiX / 2;
			multiY = multiY / 2;
			if (fabs(curAlliancePosY - y) < multiY)
			{
				if (fabs(curAlliancePosX - x) > multiX && fabs(curAlliancePosX - x) < (multiX * 3))
				{
					if (curAlliancePosX - x > 0)
					{
						allianceX--;
						curAlliancePosX = curAlliancePosX - (multiX * 2);
						turn=1;
					}
					else if (x - curAlliancePosX > 0)
					{
						allianceX++;
						curAlliancePosX = curAlliancePosX + (multiX * 2);
						turn=1;
					}
				}
			}
			else if (fabs(curAlliancePosY - y) > multiY && fabs(curAlliancePosX - x) < multiX)
			{
				if (curAlliancePosY - y > 0)
				{
					for (int p = allianceY + 1; p <= 5; p++)
					{
						boundryX = boundryX * 1.035;
						boundryY = boundryY * 1.072;
					}
					if (fabs(curAlliancePosY - y) < (boundryY + multiY))
					{
						allianceY++;
						curAlliancePosY = curAlliancePosY - (multiY + (boundryY / 2));
						turn=1;
					} 
				}
				else if (y - curAlliancePosY > 0)
				{
					for (int p = allianceY - 1; p <= 5; p++)
					{
						boundryX = boundryX * 1.035;
						boundryY = boundryY * 1.072;
					}
					if (fabs(curAlliancePosY - y) < (boundryY + multiY))
					{
						allianceY--;
						curAlliancePosY = curAlliancePosY + (multiY + (boundryY / 2));
						turn=1;
					}
				}
			}
		}
		mouseClick = false;
	}
}

void PrintText(char *text)
{
	D3DCOLOR fontcolor = D3DCOLOR_ARGB(255, 0, 0, 0);

	RECT rct;
	rct.left=10;
	rct.right=rct.left+620;
	rct.top=440;
	rct.bottom=rct.top+40;

	font1->DrawText(NULL, text, -1, &rct, DT_WORDBREAK, fontcolor );
}